package com.smasher.camera.activity

import android.annotation.SuppressLint
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.AspectRatio
import androidx.camera.core.CameraControl
import androidx.camera.core.CameraInfo
import androidx.camera.core.CameraSelector
import androidx.camera.core.FocusMeteringAction
import androidx.camera.core.FocusMeteringResult
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
import androidx.camera.core.MeteringPointFactory
import androidx.camera.core.Preview
import androidx.camera.core.TorchState
import androidx.camera.core.resolutionselector.AspectRatioStrategy
import androidx.camera.core.resolutionselector.ResolutionSelector
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import com.permissionx.guolindev.PermissionX
import com.smasher.camera.analyzer.MLQRcodeAnalyzer
import com.smasher.camera.analyzer.QRcodeAnalyzer
import com.smasher.camera.databinding.ActivityQrcodeBinding
import com.smasher.camera.other.OperationListener
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit


class QRcodeActivity : AppCompatActivity() {

    private lateinit var analysis: ImageAnalysis
    private lateinit var cameraControl: CameraControl
    private lateinit var cameraInfo: CameraInfo

    private var maxZoom: Float = 0f
    private var minZoom: Float = 0f
    private var currentZoom: Float = 0f

    /** Blocking camera operations are performed using this executor */
    private val cameraExecutor = Executors.newSingleThreadExecutor()

    private val mBinding: ActivityQrcodeBinding by lazy {
        createViewBinding()
    }

    private val useMlKitDetector by lazy {
        intent.extras?.getBoolean("useMlKitDetector") == true
    }

    val aspectRatioStrategy = AspectRatioStrategy(
        AspectRatio.RATIO_16_9, AspectRatioStrategy.FALLBACK_RULE_AUTO
    )
    val resolutionSelector = ResolutionSelector.Builder()
        .setAspectRatioStrategy(aspectRatioStrategy)
        .setAllowedResolutionMode(ResolutionSelector.PREFER_HIGHER_RESOLUTION_OVER_CAPTURE_RATE)
        .build()


    private fun createViewBinding(): ActivityQrcodeBinding {
        return ActivityQrcodeBinding.inflate(layoutInflater)
    }

    @SuppressLint("CheckResult", "ClickableViewAccessibility")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(mBinding.root)
        ViewCompat.setOnApplyWindowInsetsListener(mBinding.rootView) { view, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            view.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
        mBinding.actionBack.setOnClickListener { finish() }
        mBinding.previewContainer.setPreOperationListener(mOperationListener)
        mBinding.flashSwitch.setOnClickListener(flashSwitchListener)

        val cameraPermission = android.Manifest.permission.CAMERA
        PermissionX.init(this)
            .permissions(cameraPermission)
            .request { allGranted, grantedList, deniedList ->
                Log.i(TAG, "grantedList = $grantedList")
                Log.i(TAG, "deniedList = $deniedList")
                if (allGranted) {
                    initWithPermission(mBinding.viewFinder)
                } else {
                    Toast.makeText(
                        this,
                        "These permissions are denied: $deniedList",
                        Toast.LENGTH_LONG
                    ).show()
                }
            }

    }


    private fun initWithPermission(viewFinder: PreviewView) {
        viewFinder.post {
            // Initialize our background executor
            val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
            cameraProviderFuture.addListener({

                analysis = ImageAnalysis.Builder().apply {
                    setBackpressureStrategy(STRATEGY_KEEP_ONLY_LATEST)
                    setResolutionSelector(resolutionSelector)
                    setTargetRotation(viewFinder.display.rotation)
                }.build()
                analysis.setAnalyzer(cameraExecutor, createAnalyzer())

                // CameraProvider
                val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

                // 绑定预览
                bindPreview(cameraProvider)

            }, ContextCompat.getMainExecutor(this))
        }
    }

    private fun bindPreview(cameraProvider: ProcessCameraProvider) {
        val cameraSelector = CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build()
        // 获取相机当前角度
        val rotation = mBinding.viewFinder.display.rotation
        Log.e(TAG, "rotation: $rotation")
        val refreshRate = mBinding.viewFinder.display.refreshRate
        Log.d(TAG, "refreshRates: $refreshRate")
        val supportedRefreshRates = mBinding.viewFinder.display.supportedRefreshRates
        Log.d(TAG, "supportedRefreshRates: ${supportedRefreshRates.contentToString()}")

        val preview = Preview.Builder()
            .setTargetRotation(rotation)
            .setResolutionSelector(resolutionSelector)
            .build()

        // Attach the viewfinder's surface provider to preview use case
        preview.surfaceProvider = mBinding.viewFinder.surfaceProvider

        // Must unbind the use-cases before rebinding them
        cameraProvider.unbindAll()
        val camera = cameraProvider.bindToLifecycle(
            this,
            cameraSelector,
            preview,
            analysis
        )

        // For performing operations that affect all outputs.
        cameraControl = camera.cameraControl

        // For querying information and states.
        cameraInfo = camera.cameraInfo

        cameraInfo.zoomState.observe(this) { zoomState ->
            currentZoom = zoomState.zoomRatio
            maxZoom = zoomState.maxZoomRatio
            minZoom = zoomState.minZoomRatio
            Log.d(TAG, "zoomState: maxZoom=$maxZoom, minZoom=$minZoom, currentZoom=$currentZoom")
        }
    }


    private fun createAnalyzer(): ImageAnalysis.Analyzer {
        return if (useMlKitDetector) {
            Log.i(TAG, "use MLQRcodeAnalyzer")
            MLQRcodeAnalyzer(this::onResult)
        } else {
            Log.i(TAG, "use QRcodeAnalyzer")
            QRcodeAnalyzer(this::onResult)
        }
    }

    override fun onResume() {
        super.onResume()
        // Before setting full screen flags, we must wait a bit to let UI settle; otherwise, we may
        // be trying to set app to immersive mode before it's ready and the flags do not stick
        window.decorView.postDelayed({
            // 适配系统窗口布局
            WindowCompat.setDecorFitsSystemWindows(window, false)
            // 隐藏系统 UI（兼容全版本）
            val insetsController = WindowInsetsControllerCompat(window, window.decorView)
            insetsController.hide(WindowInsetsCompat.Type.systemBars())
            insetsController.hide(WindowInsetsCompat.Type.statusBars())

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                window.setDecorFitsSystemWindows(false)
            } else {
                window.decorView.systemUiVisibility = FLAGS_FULLSCREEN
            }

        }, IMMERSIVE_FLAG_TIMEOUT)
    }


    private fun onResult(value: String) {
        mBinding.qrResult.post {
            if (mBinding.qrResult.text == value) return@post
            mBinding.qrResult.text = value
            setResult(RESULT_OK, Intent().apply {
                putExtras(Bundle().apply {
                    putString(QRCODE_RESULT, value)
                })
            })
            finish()
        }
    }

    override fun onDestroy() {
        analysis.clearAnalyzer()
        cameraExecutor.shutdown()
        super.onDestroy()
    }

    private val mOperationListener = object : OperationListener {
        override fun zoomLarger() {
            zoomScaleIn()
        }

        override fun ZoomSmaller() {
            zoomScaleOut()
        }

        override fun click(x: Float, y: Float) {
            Log.d(TAG, "click: 对焦")
            focussss(x, y)
        }

        override fun doubleClick(x: Float, y: Float) {
            // 双击放大缩小
            Log.d(TAG, "doubleClick: 缩放")
            doubleClickZoom()
        }

        override fun longClick(x: Float, y: Float) {

        }
    }

    private fun zoomScaleIn() {
        val zoomRatio = cameraInfo.zoomState.value?.zoomRatio
        if (zoomRatio != null && zoomRatio < maxZoom) {
            cameraControl.setZoomRatio((zoomRatio + 0.1f))
        }
    }

    private fun zoomScaleOut() {
        val zoomRatio = cameraInfo.zoomState.value?.zoomRatio
        if (zoomRatio != null && zoomRatio > minZoom) {
            cameraControl.setZoomRatio((zoomRatio - 0.1f))
        }
    }

    private fun doubleClickZoom() {
        val zoomRatio = cameraInfo.zoomState.value?.zoomRatio
        if (zoomRatio != null && zoomRatio < maxZoom) {
            cameraControl.setZoomRatio((zoomRatio + 0.5f))
        } else {
            cameraControl.setZoomRatio(minZoom)
        }
    }

    private fun focussss(x: Float, y: Float) {
        val factory: MeteringPointFactory =
            mBinding.viewFinder.meteringPointFactory
        val point = factory.createPoint(x, y)
        // auto calling cancelFocusAndMetering in 3 seconds
        val action = FocusMeteringAction.Builder(point, FocusMeteringAction.FLAG_AF)
            .setAutoCancelDuration(3, TimeUnit.SECONDS)
            .build()

        val future = cameraControl.startFocusAndMetering(action)
        future.addListener({
            try {
                val result = future.get() as FocusMeteringResult
                if (result.isFocusSuccessful) {
                    Log.d("CameraFocus", "✅ 对焦成功")
                } else {
                    Log.d("CameraFocus", "❌ 对焦失败")
                }

            } catch (e: Exception) {
                Log.e("CameraFocus", e.message.toString())
            }
        }, ContextCompat.getMainExecutor(this))
    }

    private val flashSwitchListener = object : View.OnClickListener {
        override fun onClick(v: View?) {
            val flashUnit = cameraInfo.hasFlashUnit()
            if (flashUnit) {
                val isTorchOn = cameraInfo.torchState.value == TorchState.ON
                cameraControl.enableTorch(!isTorchOn)
            }
        }
    }


    companion object {

        private const val TAG = "QRcodeActivity"

        private const val IMMERSIVE_FLAG_TIMEOUT = 500L

        const val QRCODE_RESULT = "QRCODE_RESULT"

        @Suppress("DEPRECATION")
        private const val FLAGS_FULLSCREEN =
            View.SYSTEM_UI_FLAG_LOW_PROFILE or
                    View.SYSTEM_UI_FLAG_FULLSCREEN or
                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
                    View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or
                    View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
                    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
    }
}

